#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/serial.h>
#include <dirent.h>

#include <sys/poll.h>

#include "impl.h"

#define DEV_DIR "/dev/"

typedef struct
{
    int fd;

    struct termios oldSettings;
    struct termios portSettings;

    int flags;
    struct serial_icounter_struct counters;

    int waitFlags;
    struct serial_icounter_struct waitCounters;

} CommInfoData;

int createLockFile(char *lockfile)
{
    int resultError = 0;
    int fd;

    mode_t n = umask(022);

    if ((fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0666)) >= 0)
    {
        //criando lock file compativel com UUCP-1.2
        char buf[12];
        snprintf(buf, sizeof(buf),  "%10d\n", getpid());
        buf[sizeof(buf) - 1] = 0;
        if (write(fd, buf, strlen(buf)) < (ssize_t)strlen(buf))
        {
            resultError = EBADF;
            unlink(lockfile);
        }
        close(fd);
    }
    else
    {
        resultError = errno;
    }

    umask(n);
    return resultError;
}

long getLockPID(char *lockfile)
{
    char buf[12];
    long pid = 0;

    int fd = open(lockfile, O_RDONLY);
    if(fd<0) return 0;

    int sz = read(fd, buf, 12);
    if(sz==-1) goto END;

    int i=0;
    while( (i<sz) && (buf[i]==' ') ) ++i;

    int j;
    for(j=i; j<sz; j++)
    {
        if(buf[j]=='\n')
        {
            buf[j] = 0;
            pid = atol(&buf[i]);
        }
    }

END:
    close(fd);

    return pid;
}

int lockPort(char *port)
{
    char lockfile[128];

    sprintf(lockfile,"/var/lock/LCK..%s",port);

    int err = createLockFile(lockfile);
    if(!err) return 1;

    int result = 0;
    if(err==EEXIST)
    {
        long pid = getLockPID(lockfile);

        if( (pid>0) && (kill(pid,0)==-1) && (errno==ESRCH) ) //processo dono do lock nao existe
        {
            if(unlink(lockfile)==-1)
            {
                fprintf(stderr,"ERROR: Unable to remove stale lockfile %s\n",lockfile);
            }
            else
            {
                err = createLockFile(lockfile);
                if(!err) result = 1;
                else goto createERR;
            }
        }
        else if(pid==0)
        {
            fprintf(stderr,"ERROR: Unable to read PID owner of lockfile %s\n",lockfile);
        }
    }
    else
    {
        goto createERR;
    }

    return result;

createERR:
    fprintf(stderr,"ERROR: Unable to create lockfile %s",lockfile);
    switch(err)
    {
    case EEXIST: fprintf(stderr," (File already exists)\n"); break;
    case EACCES: fprintf(stderr," (Permission denied)\n"); break;
    default: fprintf(stderr,"\n"); break;
    }

    return 0;
}

void unlockPort(char *port)
{
    char lockfile[128];

    sprintf(lockfile,"/var/lock/LCK..%s",port);
    unlink(lockfile);
}

char *findPorts()
{
    char *comPortPrefix[] = {"ttyS","ttyUSB","ttyAMA","ttyACM","rfcomm","ircomm",0};
    char port[32];
    char *portNames=0;
    int portNamesSz = 0;
    int portNamesBufSz = 0;
    int i,n=0;
    DIR *dir = opendir(DEV_DIR);
    struct dirent *dirent;

    if(!dir) return 0;

    while(dirent = readdir(dir))
    {
        if(dirent->d_type == DT_DIR) continue;
        if(dirent->d_type == DT_SOCK) continue;

	int prefixIndex;
        for(prefixIndex = 0; comPortPrefix[prefixIndex]; prefixIndex++)
        {
            if(strstr(dirent->d_name,comPortPrefix[prefixIndex]))
            {
                sprintf(port,"/dev/%s",dirent->d_name);

                int fd = open(port, O_RDONLY | O_NOCTTY | O_NDELAY);
                if(fd < 0) continue;

                close(fd);

                if(!lockPort(&port[5])) continue;
                unlockPort(&port[5]);

                int len = strlen(&port[5]);
                if( (portNamesSz+len) >= portNamesBufSz )
                {
                    char *result = realloc(portNames,sizeof(char)*(portNamesBufSz+128));
                    if(!result) continue;
                    portNames = result;
                    portNamesBufSz+=128;
                }

                portNames[portNamesSz] = 0;
                if(portNamesSz){strcat(portNames,";");++portNamesSz;}

                strcat(portNames,&port[5]);
                portNamesSz+=len;

                break;
            }
        }
    }

    closedir(dir);

    return portNames;
}



CommInfo *openPort(char *portName)
{
    CommInfo *ci = 0;
    CommInfoData *cid = 0;
    char port[128];

    if(!lockPort(portName)) return 0;

    sprintf(port,"/dev/%s",portName);
    int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);

    if(fd < 0) goto ERR;

    cid = (CommInfoData *)malloc(sizeof(CommInfoData));
    if(!cid) goto ERR;

    ci = (CommInfo *)malloc(sizeof(CommInfo));
    if(!ci) goto ERR;

    ci->data = cid;

    cid->flags = 0;
    memset(&cid->counters, 0, sizeof(cid->counters));
    cid->waitFlags = 0;
    memset(&cid->waitCounters, 0, sizeof(cid->waitCounters));

    if(tcgetattr(fd, &cid->oldSettings)<0) goto ERR;
    if(tcflush(fd, TCIOFLUSH)<0) goto ERR;

//    memcpy(&cid->portSettings, &cid->oldSettings, sizeof(cid->portSettings));
//    cid->portSettings.c_cflag |= (tcflag_t)  (CLOCAL | CREAD);
//    cid->portSettings.c_lflag &= (tcflag_t) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL |
//                                       ISIG | IEXTEN); //|ECHOPRT

//    cid->portSettings.c_oflag &= (tcflag_t) ~(OPOST);
//    cid->portSettings.c_iflag &= (tcflag_t) ~(INLCR | IGNCR | ICRNL | IGNBRK);
#ifdef IUCLC
//    cid->portSettings.c_iflag &= (tcflag_t) ~IUCLC;
#endif
#ifdef PARMRK
//    cid->portSettings.c_iflag &= (tcflag_t) ~PARMRK;
#endif


    memset(&cid->portSettings, 0, sizeof(cid->portSettings));
//    cid->portSettings.c_cflag = B2400 | CS8 | CLOCAL | CREAD;
    cid->portSettings.c_cflag |= (CLOCAL | CREAD);
    cid->portSettings.c_iflag = IGNPAR;
    cid->portSettings.c_oflag = 0;
    cid->portSettings.c_lflag = 0;
    cid->portSettings.c_cc[VMIN] = 0;      //blocks waiting for n bytes
    cid->portSettings.c_cc[VTIME] = 0;     //blocks for N*100 mSec
    cid->portSettings.c_cc[VINTR] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VQUIT] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VSTART] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VSTOP] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VSUSP] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VEOF] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VEOL] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VERASE] = _POSIX_VDISABLE;
    cid->portSettings.c_cc[VKILL] = _POSIX_VDISABLE;

    if(tcsetattr(fd, TCSANOW, &cid->portSettings)<0) goto ERR;
    memcpy(ci->portName, portName, strlen(portName)+1);
    usleep(3000);

    cid->fd = fd;
    return ci;

ERR:
    unlockPort(portName);
    if(fd>=0) close(fd);
    if(ci) free(ci);
    if(cid) free(cid);

    return 0;
}

int setBlockOpts(CommInfo *ci, int block)
{
    CommInfoData *cid = ci->data;
    int lastVMIN = cid->portSettings.c_cc[VMIN];

    cid->portSettings.c_cc[VMIN] = block?1:0;
    if(tcsetattr(cid->fd, TCSANOW, &cid->portSettings)<0) goto ERR;

    int flags = fcntl(cid->fd, F_GETFL);
    if(flags==-1) goto ERR;;

    if(block) flags &= ~O_NDELAY;
    else flags |= O_NDELAY;

    if(fcntl(cid->fd, F_SETFL, flags)==-1) goto ERR;

    return 1;

ERR:
    cid->portSettings.c_cc[VMIN] = lastVMIN;
    tcsetattr(cid->fd, TCSANOW, &cid->portSettings);

    return 0;
}

int setBlock(CommInfo *ci)
{
    return setBlockOpts(ci, 1);
}

int setNonblock(CommInfo *ci)
{
    return setBlockOpts(ci, 0);
}

int changeFlag(CommInfo *ci, int flag, int set)
{
    CommInfoData *cid = ci->data;
    int flags;

    if(ioctl(cid->fd, TIOCMGET, &flags)<0) return 0;

    if(set) flags |= flag;
    else flags &= ~flag;

    if(ioctl(cid->fd, TIOCMSET, &flags)<0) return 0;

    return 1;
}

int enableDTR(CommInfo *ci)
{
    return changeFlag(ci, TIOCM_DTR, 1);
}

int disableDTR(CommInfo *ci)
{
    return changeFlag(ci, TIOCM_DTR, 0);
}

int enableRTS(CommInfo *ci)
{
    return changeFlag(ci, TIOCM_RTS, 1);
}

int disableRTS(CommInfo *ci)
{
    return changeFlag(ci, TIOCM_RTS, 0);
}

int getLineState(CommInfo *ci, int line)
{
    CommInfoData *cid = ci->data;
    int lineStatus;

    if(ioctl(cid->fd, TIOCMGET, &lineStatus)<0) return -1;

    return lineStatus & line;
}

int getCTS(CommInfo *ci)
{
    return getLineState(ci, TIOCM_CTS);
}

int getDSR(CommInfo *ci)
{
    return getLineState(ci, TIOCM_DSR);
}

int getRI(CommInfo *ci)
{
    return getLineState(ci, TIOCM_RI);
}

int getCD(CommInfo *ci)
{
    return getLineState(ci, TIOCM_CD);
}

int setCFlags(CommInfo *ci, int cflags)
{
    CommInfoData *cid = ci->data;
    int lastCFlags = cid->portSettings.c_cflag;

    cid->portSettings.c_cflag = cflags;
    if(tcsetattr(cid->fd, TCSANOW, &cid->portSettings)<0)
    {
        cid->portSettings.c_cflag = lastCFlags;
        return 0;
    }

    return 1;
}

int setParityNone(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, cid->portSettings.c_cflag & (~PARENB) );
}

int setParityOdd(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, cid->portSettings.c_cflag | PARENB | PARODD );
}

int setParityEven(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, (cid->portSettings.c_cflag | PARENB) & (~PARODD) );
}

int setStopBits1(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, cid->portSettings.c_cflag & (~CSTOPB) );
}

int setStopBits2(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, cid->portSettings.c_cflag | CSTOPB );
}

int setDataBits5(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, (cid->portSettings.c_cflag & (~CSIZE)) | CS5 );
}

int setDataBits6(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, (cid->portSettings.c_cflag & (~CSIZE)) | CS6 );
}

int setDataBits7(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, (cid->portSettings.c_cflag & (~CSIZE)) | CS7 );
}

int setDataBits8(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCFlags(ci, (cid->portSettings.c_cflag & (~CSIZE)) | CS8 );
}

int setCIFlags(CommInfo *ci, int cflags, int iflags)
{
    CommInfoData *cid = ci->data;
    int lastCFlags = cid->portSettings.c_cflag;
    int lastIFlags = cid->portSettings.c_iflag;

    cid->portSettings.c_cflag = cflags;
    cid->portSettings.c_iflag = iflags;
    if(tcsetattr(cid->fd, TCSANOW, &cid->portSettings)<0)
    {
        cid->portSettings.c_cflag = lastCFlags;
        cid->portSettings.c_iflag = lastIFlags;
        return 0;
    }

    return 1;
}

int setFlowNone(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCIFlags(ci, cid->portSettings.c_cflag & (~CRTSCTS), cid->portSettings.c_iflag & ~(IXON | IXOFF | IXANY) );
}

int setFlowHW(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCIFlags(ci, cid->portSettings.c_cflag | CRTSCTS, cid->portSettings.c_iflag & ~(IXON | IXOFF | IXANY) );
}

int setFlowSW(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    return setCIFlags(ci, cid->portSettings.c_cflag & (~CRTSCTS), cid->portSettings.c_iflag | IXON | IXOFF | IXANY );
}

int setBaud(CommInfo *ci, int baud)
{
    CommInfoData *cid = ci->data;
    int lastISpeed = cfgetispeed(&cid->portSettings);
    int lastOSpeed = cfgetospeed(&cid->portSettings);

    switch (baud) {
    case 300:
	cfsetispeed(&cid->portSettings,B300);
	cfsetospeed(&cid->portSettings,B300);
            break;
    case 2400:
	cfsetispeed(&cid->portSettings,B2400);
	cfsetospeed(&cid->portSettings,B2400);
            break;
    case 4800:
	cfsetispeed(&cid->portSettings,B4800);
	cfsetospeed(&cid->portSettings,B4800);
            break;
    case 9600:
	cfsetispeed(&cid->portSettings,B9600);
	cfsetospeed(&cid->portSettings,B9600);
            break;
    case 19200:
	cfsetispeed(&cid->portSettings,B19200);
	cfsetospeed(&cid->portSettings,B19200);
            break;
    case 38400:
	cfsetispeed(&cid->portSettings,B38400);
	cfsetospeed(&cid->portSettings,B38400);
            break;
    case 57600:
	cfsetispeed(&cid->portSettings,B57600);
	cfsetospeed(&cid->portSettings,B57600);
            break;
    case 115200:
	cfsetispeed(&cid->portSettings,B115200);
	cfsetospeed(&cid->portSettings,B115200);
            break;
    default:
            return 0;
    }

    if(tcsetattr(cid->fd, TCSANOW, &cid->portSettings)<0)
    {
	cfsetispeed(&cid->portSettings,lastISpeed);
	cfsetospeed(&cid->portSettings,lastOSpeed);
        return 0;
    }

    return 1;
}

int flush(CommInfo *ci)
{
    CommInfoData *cid = ci->data;

//    tcdrain(cid->fd);
    if(tcflush(cid->fd, TCIOFLUSH)<0) return 0;

    return 1;
}

int closePort(CommInfo *ci)
{
    int result = 1;

    CommInfoData *cid = ci->data;

    if(cid->fd!=-1)
    {
        flush(ci);
        close(cid->fd);
        cid->fd = -1;
    }

    unlockPort(ci->portName);

    free(cid);
    free(ci);

    return result;
}

int readPort(CommInfo *ci, u8 *buf, int len)
{
    CommInfoData *cid = ci->data;

    struct pollfd fds[1];
    fds[0].fd = cid->fd;
    fds[0].events = POLLIN | POLLERR | POLLHUP;

    int pollrc = poll(fds, 1, 0);
    if(pollrc<0) return -1;

    if( (pollrc>0) && (fds[0].revents & (POLLERR|POLLHUP)) )
    {
        return -1;
    }

    int n = read(cid->fd, buf, len);
    if(n>0) return n;
    if(n==-1) return -1;

    if( (pollrc>0) && (fds[0].revents & POLLIN) )
    {
        return -1;
    }

    return 0;
}

int writePort(CommInfo *ci, u8 *buf, int len)
{
    CommInfoData *cid = ci->data;

    return write(cid->fd, buf, len);
}

int available(CommInfo *ci)
{
    CommInfoData *cid = ci->data;
    int avail = 0;

    ioctl(cid->fd, FIONREAD, &avail);

    return avail;
}

void beginEvents(CommInfo *ci)
{
    CommInfoData *cid = ci->data;

    ioctl(cid->fd, TIOCMGET, &cid->flags);
    cid->waitFlags = cid->flags;

    ioctl(cid->fd, TIOCGICOUNT, &cid->counters);
    memcpy(&cid->waitCounters, &cid->counters, sizeof(cid->counters));
}

void fillEvents(EvInfos *infos, int flags, int lastFlags, struct serial_icounter_struct *counters, struct serial_icounter_struct *lastCounters)
{
    infos->state[E_LE] = (flags & TIOCM_LE)?1:0;
    infos->occ[E_LE] = (flags & TIOCM_LE)!=(lastFlags & TIOCM_LE);

    infos->state[E_DTR] = (flags & TIOCM_DTR)?1:0;
    infos->occ[E_DTR] = (flags & TIOCM_DTR)!=(lastFlags & TIOCM_DTR);

    infos->state[E_RTS] = (flags & TIOCM_RTS)?1:0;
    infos->occ[E_RTS] = (flags & TIOCM_RTS)!=(lastFlags & TIOCM_RTS);

    infos->state[E_ST] = (flags & TIOCM_ST)?1:0;
    infos->occ[E_ST] = (flags & TIOCM_ST)!=(lastFlags & TIOCM_ST);

    infos->state[E_SR] = (flags & TIOCM_SR)?1:0;
    infos->occ[E_SR] = (flags & TIOCM_SR)!=(lastFlags & TIOCM_SR);

    infos->state[E_CTS] = (flags & TIOCM_CTS)?1:0;
    infos->occ[E_CTS] = (flags & TIOCM_CTS)!=(lastFlags & TIOCM_CTS);
    if(counters->cts!=lastCounters->cts) infos->occ[E_CTS] = counters->cts-lastCounters->cts;

    infos->state[E_CAR] = (flags & TIOCM_CAR)?1:0;
    infos->occ[E_CAR] = (lastFlags & TIOCM_CAR)!=(flags & TIOCM_CAR);
    if(counters->dcd!=lastCounters->dcd) infos->occ[E_CAR] = counters->dcd-lastCounters->dcd;

    infos->state[E_RNG] = (flags & TIOCM_RNG)?1:0;
    infos->occ[E_RNG] = (flags & TIOCM_RNG)!=(lastFlags & TIOCM_RNG);
    if(counters->rng!=lastCounters->rng) infos->occ[E_RNG] = counters->rng-lastCounters->rng;

    infos->state[E_DSR] = (flags & TIOCM_DSR)?1:0;
    infos->occ[E_DSR] = (flags & TIOCM_DSR)!=(lastFlags & TIOCM_DSR);
    if(counters->dsr!=lastCounters->dsr) infos->occ[E_DSR] = counters->dsr-lastCounters->dsr;

    infos->occ[E_RX] = counters->rx-lastCounters->rx;
    infos->state[E_RX] = infos->occ[E_RX]!=0;

    infos->occ[E_TX] = counters->tx-lastCounters->tx;
    infos->state[E_TX] = infos->occ[E_TX]!=0;

    infos->occ[E_FRAME] = counters->frame-lastCounters->frame;
    infos->state[E_FRAME] = infos->occ[E_FRAME]!=0;

    infos->occ[E_OVERRUN] = counters->overrun-lastCounters->overrun;
    infos->state[E_OVERRUN] = infos->occ[E_OVERRUN]!=0;

    infos->occ[E_PARITY] = counters->parity-lastCounters->parity;
    infos->state[E_PARITY] = infos->occ[E_PARITY]!=0;

    infos->occ[E_BRK] = counters->brk-lastCounters->brk;
    infos->state[E_BRK] = infos->occ[E_BRK]!=0;

    infos->occ[E_BUFOVERRUN] = counters->buf_overrun-lastCounters->buf_overrun;
    infos->state[E_BUFOVERRUN] = infos->occ[E_BUFOVERRUN]!=0;
}

int pollEvents(CommInfo *ci, EvInfos *infos)
{
    CommInfoData *cid = ci->data;

    int result = 0;
    int hasFlags, hasCount;

    int lastFlags = cid->flags;

    struct serial_icounter_struct lastCounters;
    memcpy(&lastCounters, &cid->counters, sizeof(cid->counters));

    hasFlags = ioctl(cid->fd, TIOCMGET, &cid->flags);
    hasCount = ioctl(cid->fd, TIOCGICOUNT, &cid->counters);

    if( ((hasFlags!=-1) && (cid->flags!=lastFlags)) ||
        ((hasCount!=-1) && memcmp(&cid->counters,&lastCounters,sizeof(cid->counters))) )
    {
        fillEvents(infos, cid->flags, lastFlags, &cid->counters, &lastCounters);
        result = 1;
    } else {
        memset(infos, 0, sizeof(EvInfos));
    }

    struct pollfd fds[1];
    fds[0].fd = cid->fd;
    fds[0].events = POLLIN | POLLOUT | POLLERR | POLLHUP;

    int pollrc = poll(fds, 1, 0);
    if(pollrc<0) return 0;
    if(pollrc>0)
    {
        if(fds[0].revents & POLLIN)
            infos->state[E_IOIN]=infos->occ[E_IOIN]=1;

        if(fds[0].revents & POLLOUT)
            infos->state[E_IOOUT]=infos->occ[E_IOOUT]=1;

        if(fds[0].revents & POLLERR)
            infos->state[E_IOERR]=infos->occ[E_IOERR]=1;

        if(fds[0].revents & POLLHUP)
            infos->state[E_IOHUP]=infos->occ[E_IOHUP]=1;

        result = 1;
    }

    return result;
}

/*
nao retorna eventos de IO para manter conformidade com a implementacao do windows.
*/
int waitEvents(CommInfo *ci, EvInfos *infos)
{
    CommInfoData *cid = ci->data;

    int lastWaitFlags = cid->waitFlags;

    struct serial_icounter_struct lastWaitCounters;
    memcpy(&lastWaitCounters, &cid->waitCounters, sizeof(cid->waitCounters));

    while(1)
    {
        int hasFlags = ioctl(cid->fd, TIOCMGET, &cid->waitFlags);
        int hasCount = ioctl(cid->fd, TIOCGICOUNT, &cid->waitCounters);

        if(hasCount == hasFlags == -1) break;

        if( ((hasFlags!=-1) && (cid->waitFlags!=lastWaitFlags)) ||
            ((hasCount!=-1) && memcmp(&cid->waitCounters,&lastWaitCounters,sizeof(cid->waitCounters))) )
        {
            fillEvents(infos, cid->waitFlags, lastWaitFlags, &cid->waitCounters, &lastWaitCounters);
            return 1;
        }

        usleep(1000);
    }

    return 0;
}

int waitErrorEvents(CommInfo *ci, EvInfos *infos)
{
    CommInfoData *cid = ci->data;

    struct serial_icounter_struct lastWaitCounters;
    memcpy(&lastWaitCounters, &cid->waitCounters, sizeof(cid->waitCounters));

    while(ioctl(cid->fd, TIOCGICOUNT, &cid->waitCounters)!=-1)
    {
        if(memcmp(&cid->waitCounters,&lastWaitCounters,sizeof(cid->waitCounters)))
        {
            fillEvents(infos, cid->waitFlags, cid->waitFlags, &cid->waitCounters, &lastWaitCounters);
            return 1;
        }
        usleep(1000);
    }

    return 0;
}

int waitLineEvents(CommInfo *ci, EvInfos *infos)
{
    CommInfoData *cid = ci->data;

    int hasFlags, hasCount, hasEvent;

    int lastWaitFlags = cid->waitFlags;

    hasFlags = ioctl(cid->fd, TIOCMGET, &cid->waitFlags);

    if( (hasFlags!=-1) && (cid->waitFlags!=lastWaitFlags) )
    {
        fillEvents(infos, cid->waitFlags, lastWaitFlags, &cid->waitCounters, &cid->waitCounters);
        return 1;
    }

    hasEvent = ioctl(cid->fd, TIOCMIWAIT, TIOCM_LE | TIOCM_DTR | TIOCM_RTS | TIOCM_ST | TIOCM_SR |
                                         TIOCM_CTS | TIOCM_CAR | TIOCM_RNG | TIOCM_DSR);

    hasFlags = ioctl(cid->fd, TIOCMGET, &cid->waitFlags);

    if( (hasFlags!=-1) && (cid->waitFlags!=lastWaitFlags) )
    {
        fillEvents(infos, cid->waitFlags, lastWaitFlags, &cid->waitCounters, &cid->waitCounters);
        return 1;
    }

    return 0;
}

